package com.bldby.baselibrary.core.network;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.TypeReference;
import com.bldby.baselibrary.app.GlobalUtil;
import com.bldby.baselibrary.core.log.HttpLogUtil;
import com.bldby.baselibrary.core.network.networkcheck.NetWorkState;
import com.bldby.baselibrary.core.network.networkcheck.NetworkConnectChangedReceiver;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.convert.StringConvert;
import com.lzy.okgo.exception.HttpException;
import com.lzy.okgo.model.HttpHeaders;
import com.lzy.okgo.request.PostRequest;
import com.lzy.okgo.request.base.Request;
import com.lzy.okrx2.adapter.ObservableBody;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.Types;

import org.reactivestreams.Subscription;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.SocketTimeoutException;
import java.util.List;
import java.util.Map;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;

/**
 * Created by bch on 2020/5/11
 */
public abstract class BaseApiRequest extends AbsApiRequest {
    public static final MediaType JSONBody = MediaType.parse("application/json; charset=utf-8");


    /**
     * 数据解析错误(已正常返回) json错误
     */
    public static final int kErrorTypeResponsePraseError = -10000001;
    /**
     * 数据处理出错(外界对返回值的处理出现异常)
     */
    public static final int kErrorTypeResponseHandleError = -10000002;

    /**
     * 网络连接不可用
     */
    public static final int kErrorTypeNoNetworkConnect = -10000003;

    /**
     * 网络连接取消
     */
    public static final int kErrorTypeNoNetworkCancel = -10000004;
    public static final int kErrorTypeError = -10000005;

    /**
     * io
     */
    public static final int kErrorTypeResponseIOeError = -10000007;
    /**
     * 是否需要网络检测
     * 默认需要,
     */
    public boolean RequestCheckNetwork = true;

    /**
     * 是否展示 加载条
     */
    public boolean isShowLoading = false;

    /**
     * 是否展示 加载条
     */
    public boolean isKotlinJson = false;

    /**
     * 网络请求的订阅对象
     */
    private Subscription sub;
    /**
     * 请求标记
     */
    public String requestTag;
    private ApiCallBack listener;
    private RequestLevel requestLevel;

    @Override
    public void onStart() {
        HttpLogUtil.e(getAPIName(), "onStart");
        if (listener != null && listener instanceof ApiLifeCallBack) {
            ((ApiLifeCallBack) listener).onStart();
        }
    }


    /**
     * 设置请求类型
     *
     * @return
     */
    @Override
    public RequestLevel getRequestLevel() {
        return RequestLevel.POST;
    }

    //Okgo 3.0 升级以后的方法

    /**
     * 确定是什么请求方式
     *
     * @param usePost
     * @return
     */
    private Request<String, ? extends Request> getRequest(RequestLevel usePost) {
        HttpLogUtil.e(getAPIName(), "是否post" + usePost);
        switch (usePost) {
            case GET:
                return OkGo.get(getApiUrl());
            case JSONBody:
                return OkGo.post(getApiUrl());
            case POST:
                return OkGo.post(getApiUrl());
            default:
                return OkGo.post(getApiUrl());
        }
    }

    @Override
    public ParamsBuilder appendEspeciallyParams(ParamsBuilder builder) {
        return super.appendEspeciallyParams(builder);
    }

    /**
     * 设置请求策略参数
     *
     * @param req
     * @return
     */
    private Observable<String> getRequestObservable(Request<String, ?> req) {
        requestTag = this.hashCode() + "";
        req.tag(requestTag);
        Map<String, Object> build = appendParams(new ParamsBuilder()).build();
        if (requestLevel == RequestLevel.JSONBody) {
            ((PostRequest) req).upRequestBody(RequestBody.create(JSON.toJSON(build).toString(), JSONBody));
            HttpLogUtil.e(getApiUrl(), "设置参数" + JSON.toJSON(build).toString());

        } else {
            req.params(ParamsBuilder.getHttpParams(build));
            HttpLogUtil.e(getApiUrl(), "设置参数" + req.getParams().toString());

        }
        req.converter(new StringConvert());
        HttpHeaders commonHeaders = OkGo.getInstance().getCommonHeaders();
        if (commonHeaders == null) {
            commonHeaders = new HttpHeaders();
        }
        //添加头参数
        req.headers(addHeads(commonHeaders));
        return req.adapt(new ObservableBody<String>());
    }

    /**
     * 发起请求
     *
     * @param listener
     * @return
     */
    @Override
    public void call(ApiCallBack listener) {
        this.listener = listener;
        if (isShowLoading) {
            HttpLoadingUtil.setLoadingViewShow(this, true);
        }
        NetWorkState networkStatus = NetworkConnectChangedReceiver.getNetworkStatus(GlobalUtil.getApplication());
        //检查网络
        if (RequestCheckNetwork && networkStatus == NetWorkState.NONE) {
            handleError(kErrorTypeNoNetworkConnect, "网络未开启,请打开网络");
            return;
        }
        requestLevel = getRequestLevel();
        try {
            //请求流程处理
            Observable.just(requestLevel)                   //观察判断是否使用http post
                    .map(new Function<RequestLevel, Request>() {
                        @Override
                        public Request apply(RequestLevel aBoolean) throws Exception {
                            //返回okgo request对象
                            return getRequest(aBoolean);
                        }
                    }).flatMap(new Function<Request, ObservableSource<?>>() {
                @Override
                public ObservableSource<?> apply(Request request) throws Exception {
                    //设置请求参数 https策略
                    return getRequestObservable(request);
                }
            })
                    .doOnSubscribe(new Consumer<Disposable>() {
                        @Override
                        public void accept(Disposable disposable) throws Exception {
                            onStart();//发起请求前 通知callback
                        }
                    })
                    .observeOn(Schedulers.io()) //io线程
                    .map(new Function<Object, BaseApiResponse>() {
                        @Override
                        public BaseApiResponse apply(Object o) throws Exception {
                            //解析json
                            return praseJson((String) o);
                        }
                    })
                    .map(baseRsq -> praseResponse(baseRsq))      //解析base对象（errorcode extra 字段）
                    .observeOn(AndroidSchedulers.mainThread())  //切换到主线程
                    .subscribe(new Observer<Object>() {
                        @Override
                        public void onSubscribe(Disposable d) {

                        }

                        @Override
                        public void onNext(Object o) {
                            try {
                                if (o instanceof String && o.equals("null")) {
                                    handleRsponse_private(null);

                                } else {
                                    handleRsponse_private(o);
                                }
                            } catch (Exception e) {

                                handleError_private(e);
                            }

                        }

                        @Override
                        public void onError(Throwable e) {
                            handleError_private(e);
                        }

                        @Override
                        public void onComplete() {

                        }
                    });
        } catch (Exception error) {
            handleError_private(error);
        }

    }

    private void handleRsponse_private(Object rsp) {

        rsp = handleRsponseAfterTransform(rsp);
        HttpLogUtil.e(getAPIName(), "成功");

        if (listener != null) {
            listener.onAPIResponse(rsp);
        }
        //请求结束
        onFinsh();
    }

    private void handleError_private(Throwable error) {
        error.printStackTrace();
        int errorCode;
        String errorMsg = "";
        if (error instanceof ApiErrorException) {
            //后台错误
            ApiErrorException ex = (ApiErrorException) error;
            errorCode = ex.getErrorCode();
            errorMsg = ex.getErrorMsg();
        } else if (error instanceof HttpException) {
            //http错误
            int code = ((HttpException) error).code();
            errorMsg = error.getMessage();
            errorCode = code;
        } else if (error instanceof JSONException) {
            //json解析出错
            errorCode = kErrorTypeResponsePraseError;
            errorMsg = "json解析错误";
        } else if (error instanceof SocketTimeoutException) {
            errorCode = kErrorTypeError;
            errorMsg = "请求超时";
        } else if (error instanceof IOException) {
            errorCode = kErrorTypeResponseIOeError;
            errorMsg = "请求失败";
        } else {
            errorCode = kErrorTypeResponseHandleError;
            errorMsg = "数据错误";
        }

        handleError(errorCode, errorMsg);

    }

    /**
     * 解析json ,处理为公共数据模型
     *
     * @param json
     * @return
     */
    private BaseApiResponse praseJson(String json) {
        HttpLogUtil.e(getAPIName(), "解析公共model");
        HttpLogUtil.e(getAPIName(), " 数据 ： " + json);
        BaseApiResponse baseApiResponse = (BaseApiResponse) JSON.parseObject(json, getResponseType());
        return baseApiResponse;
    }

    @Override
    public Object handleRsponseBeforeTransform(Object rsp) {
        HttpLogUtil.e(getAPIName(), "handleRsponseBeforeTransform");

        return rsp;
    }


    private Object praseResponse(BaseApiResponse baseRes) throws IOException {
        HttpLogUtil.e(getAPIName(), "解析数据");

        if (!baseRes.isRequestSuccess()) {
            throw new ApiErrorException(baseRes);
        }
        Object rsp = baseRes.getData();

        if (rsp == null) {
            rsp = "";
        }
        rsp = handleRsponseBeforeTransform(rsp);
        if (isKotlinJson) {
            Moshi moshi = new Moshi.Builder()
                    .build();
//            Type listOfCardsType = Types.newParameterizedType(List.class, Bean.class);

            Type type = getDatatype().getType();
            Type kDatatype = getKDatatype();
            JsonAdapter adapter;
            if (kDatatype != null) {
                adapter = moshi.adapter(kDatatype);
            } else {
                adapter = moshi.adapter(type);
            }
            if (rsp == null || rsp.equals("")) {
                if (type instanceof List) {
                    try {
                        Object o = adapter.fromJson("[]");
                        return o;
                    } catch (IOException e) {
                        e.printStackTrace();
                        return "null";
                    }
                }
//            return JSON.parseObject("", getDatatype());
                //Rxjava不能传递空值
                return "null";
            } else {
                String s = JSON.toJSONString(rsp);
                Object o = adapter.fromJson(s);
                return o;
            }
        } else {
            if (rsp == null || rsp.equals("")) {
                Type type = getDatatype().getType();
                if (type instanceof List) {
                    return JSON.parseObject("[]", getDatatype());
                }
//            return JSON.parseObject("", getDatatype());
                //Rxjava不能传递空值
                return "null";
            } else {

                return JSON.parseObject(JSON.toJSONString(rsp), getDatatype());
            }
        }

    }

    public Type getKDatatype() {
        return null;
    }

    @Override
    public Object handleRsponseAfterTransform(Object rsp) {
        HttpLogUtil.e(getAPIName(), "handleRsponseAfterTransform");

        return rsp;
    }

    @Override
    public void handleError(int errorCode, String errorMsg) {
        HttpLogUtil.e("handleError    " + getAPIName(), errorCode + "::" + errorMsg);
        //请求结束
        onFinsh();
        if (listener != null) {
            listener.onAPIError(errorCode, errorMsg);
        }
    }

    @Override
    public void onFinsh() {
        HttpLogUtil.e(getAPIName(), "onFinsh");

        if (isShowLoading) {
            HttpLoadingUtil.setLoadingViewShow(this, false);
        }
        if (listener != null && listener instanceof ApiLifeCallBack) {
            ((ApiLifeCallBack) listener).onFinsh();
        }
    }

    @Override
    public void cancelRequest() {
        HttpLogUtil.e(getAPIName(), "cancelRequest");
        OkGo.getInstance().cancelTag(requestTag);
        handleError(kErrorTypeNoNetworkCancel, "请求取消");
    }


}
